Neural Delay Control — MLP-Modulated Adaptive Delay
Adaptive delay whose per-frame mix and feedback modulation is computed by a hand-designed 30-8-2 Multi-Layer Perceptron (MLP) evaluated entirely inside Praat — no Python, no training data, pure neural architecture running in realtime-like frames.
What this does
This script implements a neural network-controlled adaptive delay effect. Unlike standard delay pedals where mix and feedback are static, this effect modulates these parameters frame-by-frame based on the audio's timbral and temporal characteristics. A 30-8-2 Multi-Layer Perceptron (MLP) processes 30 acoustic features per frame (MFCCs, delta-MFCCs, HNR, voicing, intensity, transients) and outputs two modulation signals that adjust the user's base mix and feedback levels.
Key Features:
- 30-8-2 MLP — 30 input features, 8 ReLU hidden units, 2 tanh outputs
- 266 Hand-Designed Weights — Interpretable hidden unit detectors (HNR, voicing, transients, formants, timbral change)
- 13 MFCC + 13 Delta-MFCC — Spectral envelope and timbral change sensitivity
- 6 Presets — Clean Digital, Analog Warmth, Slapback, Rhythmic Dotted, Ambient Wash, Modulated
- Frame-by-Frame Adaptation — Mix and feedback update every 20 ms (default)
- No Python Dependency — Pure Praat script, self-contained
Quick start
- In Praat, select exactly one Sound object.
- Run script… →
Neural_Delay_Control.praat. - Choose a preset from the dropdown (6 options).
- Or select "Manual" and adjust Delay_time_ms, Feedback_base, Mix_base, Number_of_repeats.
- Optionally enable lowpass filter and set cutoff (for analog warmth).
- Set Frame_step_ms (analysis resolution) and Smooth_ms (control smoothing).
- Click OK — script extracts features, runs MLP forward pass, applies adaptive delay, and creates output
originalname_neuralMLP_presetname.
MLP Architecture — 30-8-2
Network equations
Input layer: x ∈ ℝ³⁰ (normalised features per frame)
Hidden layer (ReLU): hⱼ = max(0, b1ⱼ + Σₖ w1[ⱼ,ₖ]·xₖ) — j = 1..8
Output layer (tanh): outₒ = tanh(b2ₒ + Σⱼ w2[ₒ,ⱼ]·hⱼ) — o = 1 (mix), 2 (feedback)
Final modulation: mix = clamp(base_mix + 0.4·out₁, 0.05, 0.8)
feedback = clamp(base_feedback + 0.3·out₂, 0.10, 0.7)
Hidden Units — Hand-Designed Detectors
30 Input Features per Frame
| [1]–[13] | MFCC 1–13 / 30 (normalised spectral envelope coefficients) |
| [14]–[26] | |ΔMFCC 1–13| / 30 (absolute frame-to-frame change) |
| [27] | HNR_norm — Harmonics-to-Noise Ratio normalised 0–1 |
| [28] | Voicing — 0 (unvoiced) or 1 (voiced) from Pitch tracking |
| [29] | Intensity_norm — (dB - 60) / 30 + 0.5, clamped to [0,1] |
| [30] | Transient_norm — absolute intensity difference / 20, clamped to [0,1] |
6 Presets
| Preset | Delay (ms) | Feedback base | Mix base | Repeats | Filter | Character |
|---|---|---|---|---|---|---|
| Clean Digital | 250 | 0.35 | 0.30 | 4 | off | Transparent, MLP-modulated repeats.理想 |
| Analog Warmth | 300 | 0.50 | 0.35 | 5 | LP @ 3 kHz | Warm, tape-like decay with high-frequency rolloff. |
| Slapback | 80 | 0.15 | 0.45 | 2 | off | Short, classic slapback echo. |
| Rhythmic Dotted | 375 | 0.45 | 0.35 | 4 | LP @ 4.5 kHz | Dotted eighth feel, rhythmic texture. |
| Ambient Wash | 500 | 0.60 | 0.40 | 6 | LP @ 2.5 kHz | Long, lush, reverb-like decay. |
| Modulated | 200 | 0.45 | 0.35 | 4 | LP @ 5 kHz | MLP modulation emphasised — expressive variation. |
Applications
Expressive Delay for Voice
Use case: Singing or speech with delay that responds to timbre — sustains have more presence, consonants remain clean.
Settings: Ambient Wash preset. The MLP will increase mix/feedback during sustained vowels (high HNR, high voicing) and reduce during consonants (transients, timbral change).
Rhythmic Instrument Processing
Use case: Guitar arpeggios or piano phrases where delay density follows note density.
Settings: Rhythmic Dotted preset. The MLP's timbral-change detector (h₆) responds to note transitions, creating a delay that feels "intelligent".
Glitch / Experimental Textures
Use case: Percussion or granular material where the MLP's transient response creates unpredictable modulation.
Settings: Modulated preset with short delay (200 ms). The MLP will rapidly vary mix/feedback on each transient — results can be glitchy, stutter-like, or pulsing.
Workflow: Voice → Ambient Wash
Target: Spoken word or sung phrase.
Settings: Ambient Wash preset, draw_visualization=yes.
Result: Sustained vowels trigger longer, louder repeats (MLP increases mix/feedback). Consonants remain relatively dry. The delay becomes a dynamic shadow of the voice.
Workflow: Drum loop → Modulated Slapback
Target: Drum loop.
Settings: Slapback preset, but with Modulated's MLP response (use Custom: mix_base=0.45, feedback_base=0.15, but the MLP will still react).
Result: Each drum hit triggers a slapback, but the MLP's transient detector (h₃) and timbral-change detector (h₆) will quickly reduce the second and third echoes — creates a "smart" gated slapback.
• MLP not modulating enough: Increase Frame_step_ms (lower resolution) or Smooth_ms (more smoothing) to see slower, more noticeable changes. The modulation range is ±0.4 on mix and ±0.3 on feedback from the base values — if base is near extremes, modulation is limited.
• Delay sounds static / no modulation: Ensure the input has timbral variation. Pure sine waves or white noise will produce no MFCC/delta-MFCC variation; the network outputs will be near zero. Try speech or music.
• Processing is slow: MFCC extraction is the bottleneck. Reduce duration, increase frame_step_ms (e.g., 30 ms), or use a shorter sound.
• Understanding the MLP output: Enable visualization — Panel A shows the red (mix) and green (feedback) curves over time. Compare with Panel B (HNR and voicing) to see correlations.
Visualization Panels
- Panel A: MLP control output — red = mix, green = feedback (dashed = user base values)
- Panel B: Source features — purple = HNR, orange dots = voiced frames
- Panel C: Zoom overlay (first 500 ms) — original gray, output blue
- Panel D: Full output waveform with delay tail
- Panel E: Summary — network architecture, feature set, delay parameters, and stats
w1[j,k], w2[o,j], biases). To train your own weights, you would need to: (1) export features and target modulation values, (2) train a small MLP in Python (e.g., with PyTorch or scikit-learn), (3) convert the weights back to Praat array assignments. The architecture is deliberately small (266 parameters) to make such experimentation feasible.